﻿using EnvDTE;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using Winning.SolutionManager.Util;

namespace Winning.SolutionManager
{
    public partial class FormMain : Form
    {
        private int tickts = 0;
        private Dictionary<string, Dictionary<string, string>> dictOutputDirs = new Dictionary<string, Dictionary<string, string>>();
        private DTE dte;
        private List<Project> lstAllProjects = new List<Project>();
        private const string DIR_MASK = "(^//.|^/|^[a-zA-Z])?:?/.+(/$)?";
        private bool isLoading = false;
        public FormMain()
        {
            InitializeComponent();
        }

        public FormMain(DTE dte): this()
        {
            this.dte = dte;
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            if (timer1.Tag == null)
            {
                timer1.Tag = this;
                this.LoadData();
            }
            if (tickts < 100) tickts++;
            if (tickts == 6) lblMessage.Text = string.Empty;
        }

        private void ShowMessage(string message, bool success = true)
        {
            if (success) lblMessage.ForeColor = Color.Green;
            else lblMessage.ForeColor = Color.Red;
            lblMessage.Text = message;
            tickts = 0;
        }

        private void btnOBrowser_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dialog = new FolderBrowserDialog();
            var dialogResult = dialog.ShowDialog();
            if (dialogResult == DialogResult.OK) txtOutputDir.Text = dialog.SelectedPath;
        }

        internal List<string> GetSolutionPlatforms(ref string current)
        {
            List<string> listPlatforms = new List<string>();
            if (this.lstAllProjects.Count == 0) return listPlatforms;
            if (this.lstAllProjects[0].ConfigurationManager.SupportedPlatforms != null) listPlatforms = ((object[])this.lstAllProjects[0].ConfigurationManager.SupportedPlatforms).Select(p => Convert.ToString(p)).ToList();
            if (this.lstAllProjects[0].ConfigurationManager.ActiveConfiguration != null) current = this.lstAllProjects[0].ConfigurationManager.ActiveConfiguration.PlatformName;
            for (int i = 1; i < this.lstAllProjects.Count; i++)
            {
                var proj = this.lstAllProjects[i];
                if (proj.ConfigurationManager.SupportedPlatforms == null) continue;
                var arr = (object[])proj.ConfigurationManager.SupportedPlatforms;
                if (arr == null || arr.Length == 0) continue;
                foreach(object p in arr)
                {
                    if (!listPlatforms.Contains(Convert.ToString(p))) listPlatforms.Add(Convert.ToString(p));
                }
            }
            return listPlatforms;
        }

        private object GetConfigurationValue(Project project, string configuration, string platform, string item)
        {
            try
            {
                return project.ConfigurationManager.Item(configuration, platform).Properties.Item(item).Value;
            }
            catch
            {
                return null;
            }
            
        }

        private object GetProjectProperty(Project project, string property)
        {
            try
            {
                return project.Properties.Item(property).Value;
            }
            catch
            {
                return string.Empty;
            }
        }

        private void SetConfigurationValue(Project project, string configuration, string platform, string item, object value)
        {
            try
            {
                project.ConfigurationManager.Item(configuration, platform).Properties.Item(item).Value = value;
            }
            catch
            {
                
            }
        }

        internal List<string> GetSolutionConfigurations(ref string current)
        {
            List<string> listConfigurations = new List<string>();
            if (this.lstAllProjects.Count == 0) return listConfigurations;
            if (this.lstAllProjects[0].ConfigurationManager.ConfigurationRowNames != null) listConfigurations = ((object[])this.lstAllProjects[0].ConfigurationManager.ConfigurationRowNames).Select(p => Convert.ToString(p)).ToList();
            if (this.lstAllProjects[0].ConfigurationManager.ActiveConfiguration != null) current = this.lstAllProjects[0].ConfigurationManager.ActiveConfiguration.ConfigurationName;
            if (listConfigurations.Count == 0 || this.lstAllProjects.Count == 1) return listConfigurations;
            for (int i = 1; i < this.lstAllProjects.Count; i++)
            {
                var proj = this.lstAllProjects[i];
                if (proj.ConfigurationManager.ConfigurationRowNames == null) return listConfigurations = new List<string>();
                var arr = (object[])proj.ConfigurationManager.ConfigurationRowNames;
                listConfigurations.RemoveAll(p => !arr.Any(p1 => Convert.ToString(p1) == p));
                if (listConfigurations.Count == 0) return listConfigurations = new List<string>();
            }
            return listConfigurations;
        }

        internal void LoadProjects() 
        {
            this.lstAllProjects = DTEHelper.GetSolutionProjects(this.dte.Solution);
        }

        private void FormMain_Load(object sender, EventArgs e)
        {
            this.isLoading = true;
            timer1.Start();
        }

        private void LoadData()
        {
            this.btnOk.Enabled = false;
            this.btnCancel.Enabled = false;

            this.ShowMessage("正在加载所有项目信息...");
            Application.DoEvents();
            this.lstAllProjects = DTEHelper.GetSolutionProjects(this.dte.Solution);

            this.ShowMessage("正在加载上次保存的配置...");
            Application.DoEvents();
            var mgr = Winning.SolutionManager.ConfiurationManager.Config;
            mgr.SavePath = this.GetSolutionDirectory();
            mgr.Load();

            this.ShowMessage("正在加载解决方案基本信息...");
            Application.DoEvents();
            this.LoadSolutionBaseInfo(mgr);

            this.ShowMessage("正在加载解决方案项目引用列表...");
            Application.DoEvents();
            this.LoadSolutionReferences();

            this.ShowMessage("正在加载解决方案项目引用列表...");
            Application.DoEvents();
            this.LoadSolutionProductInfo(mgr);

            this.lblMessage.Text = string.Empty;
            this.btnOk.Enabled = true;
            this.btnCancel.Enabled = true;

            this.isLoading = false;
        }

        private void LoadSolutionProductInfo(Winning.SolutionManager.ConfiurationManager mgr)
        {
            Action<Control> fnUpdate = null;
            fnUpdate = c =>{
                if (c.Tag != null && Convert.ToString(c.Tag).Length > 0){
                    var val = Convert.ToString(mgr["product_" + c.Tag.ToString()]);
                    if(string.IsNullOrEmpty(val)) val = Convert.ToString(this.GetProjectProperty(this.lstAllProjects[0], c.Tag.ToString()));
                    c.Text = val ?? string.Empty;
                }
                foreach (Control sc in c.Controls) fnUpdate(sc);
            };
            fnUpdate(tabProductInfo);
        }

        private void LoadSolutionReferences()
        {
            DataTable table = new DataTable();
            table.Columns.AddRange(new DataColumn[] { 
                new DataColumn("depends",typeof(string)),
                new DataColumn("file",typeof(string)),
                new DataColumn("copy",typeof(bool)),
                new DataColumn("action",typeof(string)),
                new DataColumn("remove",typeof(string)),
                new DataColumn("project", typeof(string)),
                new DataColumn("assembly", typeof(string)),
                new DataColumn("reference", typeof(int)),
                new DataColumn("status", typeof(int)),
            });
            foreach(Project project in this.lstAllProjects)
            {
                var vsproj = project.Object as VSLangProj.VSProject;
                foreach (VSLangProj.Reference reference in vsproj.References)
                {
                    var path = reference.Path;
                    if (path == null || path.Trim().Length == 0) continue;
                    var rows = table.Select("file = '" + path + "'");
                    if (rows.Length == 0)
                    {
                        table.Rows.Add(new object[] { project.Name + ";", path, reference.CopyLocal, "更改","移除引用", reference.SourceProject == null ? string.Empty : reference.SourceProject.Name, path, 0,1 });
                    }
                    else
                    {
                        rows[0]["copy"] = (bool)rows[0]["copy"] || reference.CopyLocal;
                        rows[0]["depends"] = Convert.ToString(rows[0]["depends"]) + "\n" + project.Name + ";";
                        if (reference.SourceProject != null) rows[0]["project"] = reference.SourceProject.Name;
                    }
                }
            }
            var view = table.DefaultView;
            view.Sort = "file desc";
            table = view.ToTable();
            table.AcceptChanges();
            this.dataGridView1.DataSource = table;
            foreach (DataGridViewColumn col in dataGridView1.Columns) col.Visible = "file,copy,action,remove".IndexOf(col.DataPropertyName ?? "NONE") >= 0;
        }

        private void LoadSolutionBaseInfo(Winning.SolutionManager.ConfiurationManager mgr)
        {
            //cboConfiguration
            string currentConfiguration = string.Empty;
            var configuations = this.GetSolutionConfigurations(ref currentConfiguration);
            this.cboConfiguration.Items.Clear();
            this.cboConfiguration.Items.AddRange(configuations.ToArray());
            if (currentConfiguration != null && configuations.Exists(c => c == currentConfiguration)) this.cboConfiguration.SelectedIndex = configuations.FindIndex(c => c == currentConfiguration);

            //cboPlatforms
            string currentPlatform = string.Empty;
            var platforms = this.GetSolutionPlatforms(ref currentPlatform);
            this.cboPlatforms.Items.Clear();
            this.cboPlatforms.Items.AddRange(platforms.ToArray());
            if (currentPlatform != null && platforms.Exists(p => p == currentPlatform)) this.cboPlatforms.SelectedIndex = platforms.FindIndex(p => p == currentPlatform);

            //txtOutputDir
            dictOutputDirs.Clear();
            txtOutputDir.Text = string.Empty;
            foreach (string configuration in configuations)
            {
                dictOutputDirs[configuration] = new Dictionary<string, string>();
                foreach (string platform in platforms)
                {
                    string strOutputDir = Convert.ToString(mgr["output_dir_" + configuration.Replace(" ", "_") + "_" + platform.Replace(" ", "_")]);
                    if (string.IsNullOrEmpty(strOutputDir) || !Regex.IsMatch(strOutputDir, DIR_MASK)) strOutputDir = Convert.ToString(this.GetConfigurationValue(this.lstAllProjects[0], configuration, platform, "OutputPath"));
                    if (strOutputDir == null || strOutputDir.Trim().Length == 0) strOutputDir = "bin\\" + configuration;
                    dictOutputDirs[configuration][platform] = strOutputDir;
                    if (configuration == currentConfiguration && platform == currentPlatform) txtOutputDir.Text = strOutputDir;
                }
            }
            //lbxRefrenceDir
            lbxRefrenceDir.Items.Clear();
            string strReferencePaths = Convert.ToString(mgr["reference_paths"]);
            if(strReferencePaths != null && strReferencePaths.Trim().Length > 0)
            {
                var paths = strReferencePaths.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
                foreach (string p in paths) lbxRefrenceDir.Items.Add(p);
            }
            else
            {
                List<string> listRef = new List<string>();
                foreach(Project project in this.lstAllProjects)
                {
                    strReferencePaths = Convert.ToString(this.GetProjectProperty(project, "ReferencePath"));
                    if (strReferencePaths == null || strReferencePaths.Trim().Length == 0) continue;
                    var paths = strReferencePaths.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (string p in paths)
                    {
                        if (!listRef.Contains(p.TrimEnd('/', '\\'))) listRef.Add(p.TrimEnd('/', '\\'));
                    }
                }
                lbxRefrenceDir.Items.AddRange(listRef.ToArray());
            }
            //txtCmdBeforeBuild
            this.txtCmdBeforeBuild.Text = string.Empty;
            string strBeforeBuild = Convert.ToString(mgr["before_build"]);
            if (strBeforeBuild == null || strBeforeBuild.Trim().Length == 0) strBeforeBuild = Convert.ToString(this.lstAllProjects[0].Properties.Item("PreBuildEvent").Value);
            txtCmdBeforeBuild.Text = strBeforeBuild;

            //txtCmdAfterBuild
            this.txtCmdAfterBuild.Text = string.Empty;
            string strAfterBuild = Convert.ToString(mgr["after_build"]);
            if (strAfterBuild == null || strAfterBuild.Trim().Length == 0) strAfterBuild = Convert.ToString(this.lstAllProjects[0].Properties.Item("PostBuildEvent").Value);
            txtCmdAfterBuild.Text = strAfterBuild;
        }
        private string GetSolutionDirectory()
        {
            if (this.dte != null && this.dte.Solution != null) return Path.GetDirectoryName(dte.Solution.FullName) + "\\";
            return string.Empty;
        }

        

        private void btnOk_Click(object sender, EventArgs e)
        {
            btnOk.Enabled = false;
            bool success = true;
            if(this.dte != null && this.dte.Solution != null)
            {
                var projects = this.lstAllProjects;
                var configuration = this.cboConfiguration.Text.Trim();
                var platform = this.cboPlatforms.Text.Trim();
                int index = 0;
                int count = projects.Count;
                foreach(var project in projects)
                {
                    try
                    {
                        this.UpdateProjectBaseInfo(project, configuration, platform);//设置基本信息
                        this.UpdateProjectRefrences(project, this.lstAllProjects);//设置引用信息
                        this.UpdateProductInfo(project);//设置产品信息
                        this.ShowMessage(string.Format("正在设置，请稍等... (进度:{0}/{1})", ++index, count));
                    }
                    catch(Exception ex)
                    {
                        ShowMessage(ex.Message, false);
                        success = false;
                    }
                    finally
                    {
                        try
                        {
                            this.SaveProjectUpdates(project);//保存更改。
                        }
                        catch(Exception exx)
                        {
                            ShowMessage(exx.Message, false);
                            success = false;
                        }
                    }
                    Application.DoEvents();
                }
                btnOk.Text = "确定(&O)";
            }
            btnOk.Enabled = true;
            if(success) this.Close();
        }

        private void SaveProjectUpdates(Project project)
        {
            string path = Convert.ToString(project.Properties.Item("FullPath").Value);
            string name = Convert.ToString(project.Properties.Item("FileName").Value);
            FileInfo info = new FileInfo(Path.Combine(path, name));
            bool readOnly = info.IsReadOnly;
            if (readOnly) info.IsReadOnly = false;//no prompt
            project.Save();
            info.IsReadOnly = readOnly;
        }

        private void UpdateProductInfo(Project project)
        {
            Action<Control> fnUpdate = null;
            fnUpdate = c =>{
                if (c.Tag != null && Convert.ToString(c.Tag).Length > 0 && c.Text.Trim().Length > 0){
                    var prop = project.Properties.Item(c.Tag);
                    if (prop != null) prop.Value = c.Text.Replace("_", string.Empty);
                }
                foreach (Control sc in c.Controls) fnUpdate(sc);
            };
            fnUpdate(tabProductInfo);
        }

        private void UpdateProjectRefrences(Project project, List<Project> slnProjects)
        {
            var vsproj = project.Object as VSLangProj.VSProject;
            var table = this.dataGridView1.DataSource as DataTable;
            var tmpTable = table.GetChanges(DataRowState.Modified);
            if (tmpTable == null || tmpTable.Rows.Count == 0) return;

            var rows = tmpTable.Select(string.Format("depends like '%{0};%'", project.Name));
            if (rows.Length == 0) return;

            var listReferences = new List<VSLangProj.Reference>();
            foreach (VSLangProj.Reference reference in vsproj.References) listReferences.Add(reference);


            foreach(VSLangProj.Reference reference in listReferences)
            {
                foreach (DataRow row in rows)
                {
                    if(Convert.ToString(row["assembly"]) == reference.Path)
                    {
                        bool isChanged = false;
                        if ((int)row["status"] == -99)
                        {
                            reference.Remove();
                            isChanged = true;
                        }
                        else if(Convert.ToString(row["file"]) != Convert.ToString(row["assembly"]))
                        {
                            int type = 0;
                            if(int.TryParse(Convert.ToString(row["reference"]), out type) && type > 0)
                            {
                                if (type == 1 && string.IsNullOrEmpty(Convert.ToString(row["project"])))//更改引用为项目
                                {
                                    var refProject = slnProjects.Find(pro => pro.Name == Convert.ToString(row["file"]));
                                    if(refProject != null)
                                    {
                                        reference.Remove();
                                        var newReference = vsproj.References.AddProject(refProject);
                                        newReference.CopyLocal = (bool)row["copy"];
                                        isChanged = true;
                                    }
                                }
                                else if (type == 2)//更改引用为程序集。
                                {
                                    reference.Remove();
                                    var newReference = vsproj.References.Add(Convert.ToString(row["file"]));
                                    newReference.CopyLocal = (bool)row["copy"];
                                    isChanged = true;
                                }
                            }
                        }
                        if (!isChanged) reference.CopyLocal = (bool)row["copy"];
                        break;
                    }
                }
            }
        }

        private void UpdateProjectBaseInfo(Project project, string configuration, string platform)
        {
            this.SetConfigurationValue(project, configuration, platform, "OutputPath", txtOutputDir.Text.Trim());
            List<string> lstReferencePaths = new List<string>();
            string strReferencePaths = Convert.ToString(project.Properties.Item("ReferencePath").Value);//lbxRefrenceDir.Items.Cast<string>().ToList();
            if (strReferencePaths != null && strReferencePaths.Trim().Length > 0) lstReferencePaths.AddRange(strReferencePaths.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(p => p.TrimEnd('/', '\\')).ToArray());
            foreach(string path in this.lbxRefrenceDir.Items)
            {
                if (path.EndsWith("[删除]")) lstReferencePaths.RemoveAll(p => p == path.Replace("[删除]",string.Empty));
                else if (!lstReferencePaths.Exists(p => p == path)) lstReferencePaths.Add(path);
            }
            project.Properties.Item("ReferencePath").Value = string.Join(";", lstReferencePaths);

            project.Properties.Item("PreBuildEvent").Value = txtCmdBeforeBuild.Text.Trim();

            project.Properties.Item("PostBuildEvent").Value = txtCmdAfterBuild.Text.Trim();
        }

        private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (this.isLoading) return;
            try
            {
                var mgr = Winning.SolutionManager.ConfiurationManager.Config;
                foreach(string configuration in dictOutputDirs.Keys)
                {
                    foreach (string platform in dictOutputDirs[configuration].Keys) mgr["output_dir_" + configuration.Replace(" ", "_") +"_"+ platform.Replace(" ", "_")] = dictOutputDirs[configuration][platform];
                }

                if (lbxRefrenceDir.Items.Count > 0) mgr["reference_paths"] = string.Join(";", lbxRefrenceDir.Items.Cast<string>().Where(p => !p.EndsWith("[删除]")).ToList());
                if (txtCmdBeforeBuild.Text.Trim().Length > 0) mgr["before_build"] = txtCmdBeforeBuild.Text.Trim();
                if (txtCmdAfterBuild.Text.Trim().Length > 0) mgr["after_build"] = txtCmdAfterBuild.Text.Trim();

                //product infomation.
                Action<Control> fnUpdate = null;
                fnUpdate = c =>{
                    if (c.Tag != null && Convert.ToString(c.Tag).Length > 0 && c.Text.Trim().Length > 0){
                        mgr["product_" + c.Tag.ToString()] = c.Text.Trim();
                    }
                    foreach (Control sc in c.Controls) fnUpdate(sc);
                };
                fnUpdate(tabProductInfo);

                mgr.Save();
            }
            catch(Exception ex)
            {
                this.ShowMessage(ex.Message + "\n(如忽略问题,请点窗体右上角关闭按钮.)", false);
                if (e.CloseReason == CloseReason.None) e.Cancel = true;
            }
        }

        private void cboConfiguration_SelectionChangeCommitted(object sender, EventArgs e)
        {
            string configuration = this.cboConfiguration.Text.Trim();
            string platform = this.cboPlatforms.Text.Trim();
            if(dictOutputDirs.ContainsKey(configuration) && dictOutputDirs[configuration] != null && dictOutputDirs[configuration].ContainsKey(platform)) txtOutputDir.Text = dictOutputDirs[configuration][platform] ?? string.Empty;
        }

        private void txtOutputDir_TextChanged(object sender, EventArgs e)
        {
            if (this.isLoading) return;
            string configuration = this.cboConfiguration.Text.Trim();
            string platform = this.cboPlatforms.Text.Trim();
            bool isValidPath = true;
            if (!Regex.IsMatch(txtOutputDir.Text.Trim(), DIR_MASK)) isValidPath = false;
            if (isValidPath)
            {
                try
                {
                    string fullPath = Path.GetFullPath(txtOutputDir.Text.Trim());
                    dictOutputDirs[configuration][platform] = fullPath;
                }
                catch
                {
                    isValidPath = false;
                }
            }

            if(!isValidPath)
            {
                ShowMessage("无效或不存在的路径.", false);
                txtOutputDir.Focus();
                return;
            }
        }

        private void btnAddDirRef_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dialog = new FolderBrowserDialog();
            var dialogResult = dialog.ShowDialog();
            if (dialogResult == DialogResult.OK && !lbxRefrenceDir.Items.Cast<string>().Any(p => p == dialog.SelectedPath)) lbxRefrenceDir.Items.Add(dialog.SelectedPath);
        }

        private void lbxRefrenceDir_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                List<string> items = lbxRefrenceDir.Items.Cast<string>().ToList();
                if (lbxRefrenceDir.SelectedIndex >= 0 && !items[lbxRefrenceDir.SelectedIndex].EndsWith("[删除]")) items[lbxRefrenceDir.SelectedIndex] = items[lbxRefrenceDir.SelectedIndex] + "[删除]";
                lbxRefrenceDir.Items.Clear();
                lbxRefrenceDir.Items.AddRange(items.ToArray());
            }
        }

        private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            if(dataGridView1.CurrentCell.OwningColumn.Name == this.colAssembly.Name)
            {
                var table = dataGridView1.DataSource as DataTable;
                var row = table.Rows[e.RowIndex];
                MessageBox.Show(Convert.ToString(row["depends"]));
            }
        }

        private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex < 0) return;
            var rowView = dataGridView1.Rows[e.RowIndex].DataBoundItem as DataRowView;
            if (rowView == null) return;
            var row = rowView.Row;
            if (dataGridView1.CurrentCell.OwningColumn.Name == this.colUpdate.Name)
            {
                int type = 2;
                string project = Convert.ToString(row["project"]) ?? string.Empty;
                string reference = Convert.ToString(row["assembly"]);
                if (!string.IsNullOrEmpty(project))
                {
                    type = 1;
                }
                else
                {
                    project = this.lstAllProjects.Where(pro => pro.Name == Path.GetFileNameWithoutExtension(reference)).Select(p => p.Name).FirstOrDefault() ?? string.Empty;
                }


                FormReferenceUpdate form = new FormReferenceUpdate(type, reference, project);
                if(form.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    row["reference"] = form.Type;
                    row["file"] = form.Reference;
                }
            }
            else if (dataGridView1.CurrentCell.OwningColumn.Name == this.colRemove.Name)
            {
                if(MessageBox.Show("是否在所有项目中，移除对此程序集/项目的引用 ? ", "确认",MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    row["status"] = -99;// deleted state.
                    row["remove"] = Convert.ToString(row["remove"]) + "[√]";
                }
            }
        }

        private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
        {
            if (dataGridView1.IsCurrentCellDirty && dataGridView1.CurrentCell.OwningColumn.Name == this.colCopyToLocal.Name)
            {
                dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
            }
        }

        private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            if (dataGridView1.CurrentCell == null) return;
            if (dataGridView1.CurrentCell.OwningColumn.Name == this.colCopyToLocal.Name)
            {
                bool val = (bool)dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
                foreach (DataGridViewRow selRow in dataGridView1.SelectedRows)
                {
                    if (selRow.Index == e.RowIndex) continue;
                    if((bool)selRow.Cells[e.ColumnIndex].Value != val) selRow.Cells[e.ColumnIndex].Value = val;
                }
            }
        }
    }
}
